<template>
  <view class="container">
    <view class="control" id="control">
      <view class="desc">
        <uni-icons custom-prefix="iconfont" type="icon-shouye" color="#e08a27"></uni-icons>
        <span>&nbsp;提交评价或建议，鼓励骑手和商家做得更好~</span>
      </view>
      <view class="submit" :class="{ submittable: isSubmit }" @click="isSubmit && submit()">提交</view>
    </view>
    <view class="container-rol">
      <piece v-if="orderForUserEvaluate?.receivingMethod === ReceivingMethod.DELIVERY">
        <view class="rider-evaluate">
          <view class="top">
            <span class="title">您对骑手满意吗？</span>
            <span class="tis">已对骑手匿名</span>
          </view>
          <view class="rider-info">
            <view class="avatar-image">
              <image src="@/static/image/evaluate/rider.png" class="avatar-image" />
            </view>
            <span>{{
              orderForUserEvaluate?.deliveryMethod == null
                ? ''
                : DeliveryMethod.PLATFORM_DELIVERY === orderForUserEvaluate?.deliveryMethod
                  ? '平台骑手'
                  : '商家骑手'
            }}</span>
          </view>
          <span class="control-area">
            <view class="is-satisfied">
              <view
                class="button"
                :class="{ active: form.riderEvaluate.score === 0 }"
                @click="form.riderEvaluate.score = 0"
              >
                <span>不满意</span>
              </view>
              <view
                class="button"
                :class="{ active: form.riderEvaluate.score === 1 }"
                @click="form.riderEvaluate.score = 1"
              >
                <span>满意</span>
              </view>
            </view>
            <view class="rider-text">
              <quick-review
                v-if="form.riderEvaluate.score === 0"
                textarea-height="100rpx"
                :flags="[
                  '少餐/洒餐',
                  '仪表不整',
                  '送错餐品',
                  '不送上门',
                  '送达超时',
                  '送达不通知',
                  '态度不好',
                  '提前点送达'
                ]"
                @change="riderQuickReviewValueChange"
                placeholder="您的反馈会督促我们做得更好"
              />
              <quick-review
                v-if="form.riderEvaluate.score === 1"
                :flags="['快速准时', '货品完好', '仪表整洁', '风雨无阻', '礼貌热情']"
                flag-trigger-text="写评价"
                @change="riderQuickReviewValueChange"
                textarea-height="100rpx"
                placeholder="告诉骑手，激励我们做得更好"
              />
            </view>
          </span>
        </view>
      </piece>
      <piece margin-top="20rpx">
        <view class="show-evaluate">
          <view class="top">
            <span class="title">您对商家/菜品满意吗？</span>
            <checked-switch v-model="form.shopEvaluate.isAnonymous" label="匿名评价" />
          </view>
          <view class="rider-info">
            <view class="avatar-image">
              <image :src="orderForUserEvaluate?.shopLogo" class="avatar-image" />
            </view>
            <span>{{ orderForUserEvaluate?.shopName }}</span>
          </view>
          <span class="control-area">
            <view class="overall">
              <span class="label">总体</span>
              <uni-rate v-model="form.shopEvaluate.score" />
            </view>
            <view class="text">
              <textarea
                placeholder="✍️说说味道怎么样，给大家参考"
                :style="{ height: '180rpx' }"
                v-model="form.shopEvaluate.evaluate"
              />
              <view class="additional">
                <template v-for="(task, index) in uploadTask" :key="task.resource.tempFilePath">
                  <view class="additional-item">
                    <image class="image" :src="task.resource.tempFilePath" />
                    <view class="schedule" :style="{ height: task.getScheduleForCSS() }"></view>
                    <view class="remove" @click="removeTask(index)">x</view>
                  </view>
                </template>

                <view class="additional-item operation" @click="selectImages">
                  <uni-icons type="camera" size="25"></uni-icons>
                  <span>附加图片</span>
                </view>
              </view>
            </view>
            <view class="dish-good-or-bad">
              <view class="item" v-for="dish in orderForUserEvaluate?.orderDetailList" :key="dish.dishId">
                <view class="dish">
                  <image class="dish-image" :src="dish.image" />
                  <span class="dish-name">{{ dish.name }}</span>
                </view>
                <good-or-bad v-model="dish.sentiment" />
              </view>
            </view>
          </span>
        </view>
      </piece>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, onMounted, getCurrentInstance, computed, watch } from 'vue'
import Piece from '@/components/piece/index.vue'
import GoodOrBad from '@/components/good-or-bad/index.vue'
import $API from '@/api'
import { OSSUploadParams, type OSSPolicy } from '@/types/response/third-party'
import { UUIDGenerator } from '@/utils/UUID'
import { EvaluateForm } from './type'
import { DeliveryMethod } from '@/enum/DeliveryMethod'
import CheckedSwitch from '@/components/checked-switch/index.vue'
import { OrderForUserEvaluateVO } from '@/types/response/order'
import QuickReview from '@/components/quick-review/index.vue'
import StringUtils from '@/utils/StringUtils'
import { $modal } from '@/plugins'
import $store from '@/store'
import { ReceivingMethod } from '@/enum/ReceivingMethod'
const query = defineProps({
  orderId: {
    type: String,
    require: true
  }
})
// 临时变量
const orderForUserEvaluate = ref<OrderForUserEvaluateVO>()

onMounted(async () => {
  form.value.orderId = query.orderId!
  const result = await $API.order.getOrderForUserEvaluate(query.orderId!)
  if (result.success) orderForUserEvaluate.value = result.data
})

const form = ref<EvaluateForm>(new EvaluateForm())

// 调用拍照/选择图片
const uploadTask = ref<Task[]>([])
// 获取已经上传的文件（图片）
function getUploadedFileUrl() {
  const uploadCompletedImageUrlList: string[] = []
  for (let task of uploadTask.value) {
    if (task.url == null) continue
    if (task.isUploaded) uploadCompletedImageUrlList.push(task.url)
  }
  return uploadCompletedImageUrlList
}
interface Resource {
  fileType: string
  size: number
  tempFilePath: string
}
class Task {
  public resource: Resource
  public schedule: number = 0
  public isUploaded = false
  public url?: string
  constructor(resource: Resource) {
    this.resource = resource
  }
  setSchedule(schedule: number) {
    this.schedule = schedule
  }
  getScheduleForCSS() {
    return (1 - this.schedule) * 100 + '%'
  }
}
// 批量添加任务
function pushTask(tempFiles: Resource[]) {
  for (let resource of tempFiles) {
    uploadTask.value.push(new Task(resource))
  }
  // 启动上传图片任务
  callWorker()
}
// 任务清理
function removeTask(index: number) {
  uploadTask.value.splice(index, 1)
}
// 请求“工作者”上传文件
async function callWorker() {
  // 上传队列中“未启动过的”的任务
  for (let i in uploadTask.value) {
    const task = uploadTask.value[i]
    if (task.isUploaded) continue

    // 只有进度为0的才需要重新上传
    taskUpload(parseInt(i), task)
  }
}
// 任务上传
async function taskUpload(index: number, task: Task) {
  // 标记为已执行过上传
  task.isUploaded = true

  // 获取上传授权
  let policy: OSSPolicy | undefined
  while (policy == null) {
    // 获取OSS授权上传请求
    const result = await $API.thirdParty.policy()
    if (result.success) policy = result.data
  }
  // 上传操作
  let resource = task.resource
  // 组装请求文件上传参数
  const ossRequestBody: OSSUploadParams = {
    signature: policy.signature,
    ossaccessKeyId: policy.accessid,
    key: policy.dir + UUIDGenerator.gen() + '_${filename}',
    dir: policy.dir,
    host: policy.host,
    policy: policy.policy
  }
  console.log('组装的请求参数：', ossRequestBody)
  uni
    .uploadFile({
      url: policy.host, //仅为示例，非真实的接口地址
      filePath: resource.tempFilePath,
      name: 'file',
      formData: ossRequestBody,
      success: (uploadFileRes) => {
        // 组装URL
        const filename = resource.tempFilePath.substring(resource.tempFilePath.lastIndexOf('/') + 1)
        task.url = policy!.host + '/' + ossRequestBody.key.replace('${filename}', filename)

        // 业务：将上传的图片资源放到表单中
        form.value.shopEvaluate.images = getUploadedFileUrl().join(',')
      },
      fail: () => taskUpload(index, task)
    })
    .onProgressUpdate((res) => {
      //   console.log('上传进度' + res.progress)
      //   console.log('已经上传的数据长度' + res.totalBytesSent)
      //   console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend)
      task.setSchedule(res.totalBytesSent / res.totalBytesExpectedToSend)
    })
}

// 选择完后添加到上传队列中
function selectImages() {
  uni.chooseMedia({
    // 文件个数
    count: 8,
    // 文件类型
    mediaType: ['image'],
    success: ({ tempFiles }) => pushTask(tempFiles)
  })
}
// 是否可以提交
const isSubmit = computed(() => {
  // 骑手检验
  // -- 对骑手评价参数校验
  return (
    (form.value.riderEvaluate.score === 1 ||
      // 如果对骑手不满足，那需要理由
      (form.value.riderEvaluate.score === 0 &&
        (!StringUtils.isBlank(form.value.riderEvaluate.evaluate) ||
          !StringUtils.isBlank(form.value.riderEvaluate.flags)))) &&
    // -- 对商家评价参数校验
    (form.value.shopEvaluate.score >= 3 ||
      // 如果评价为差，那需要理由
      (form.value.shopEvaluate.score > 0 && !StringUtils.isBlank(form.value.shopEvaluate.evaluate)))
  )
})
// 当骑手的信息变化时，收集到表单中
function riderQuickReviewValueChange(activeFlags: string[], textValue: string) {
  form.value.riderEvaluate.flags = (activeFlags || []).join(',')
  form.value.riderEvaluate.evaluate = textValue
}
// 当菜品表态改变时，更新表单
watch(
  () => orderForUserEvaluate.value?.orderDetailList,
  (dishList) => {
    // 更新
    form.value.shopEvaluate.shopDishEvaluateList = (dishList || [])
      .map((item) => {
        if (item.sentiment === 1 || item.sentiment === 0) return { dishId: item.dishId, sentiment: item.sentiment }
        return null
      })
      .filter((item) => item != null)
  },
  { deep: true }
)

async function submit() {
  const result = await $API.order.submitOrderEvaluation(form.value)
  if (!result.success) {
    $modal.toastErrorMsg('评价失败！' + result.message)
    return
  }
  // 触发订单列表需要刷新事件
  $store.order.orderListRefreshEvent.emit()
  // 返回
  uni.navigateBack()
}

// === css vars ===
// control height
const controlHeight = ref<string>()
const instance = getCurrentInstance()
let elementQuery = uni.createSelectorQuery().in(instance)
elementQuery
  .select('#control')
  .fields({ scrollOffset: true, size: true, dataset: true, rect: true, id: true }, (res: any) => {
    controlHeight.value = res.height + 'px'
  })
  .exec()
</script>

<style scoped lang="scss">
.container {
  display: flex;
  width: 100vw;
  height: 100vh;
  background: #f5f5f5;
  flex-direction: column;

  $control-height: 80rpx;

  .control {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px 25rpx;
    background: #fefbea;
    box-shadow: 0 8px 10px -13px rgb(0 0 0 / 50%);
    box-sizing: border-box;

    .desc {
      font-size: 25rpx;
      font-weight: bold;
      color: #ee9024;
    }

    .submit {
      $submit-padding-top-size: 7px;

      padding: 7px $submit-padding-top-size * 2.5;
      font-size: 25rpx;
      font-weight: bold;
      border-radius: 15rpx;
      color: #fafafa;
      background-color: #bdbdbd;
    }

    .submittable {
      color: #12131b !important;
      background: linear-gradient(to right, #fde651, #fedc1b) !important;
    }
  }

  .container-rol {
    margin-top: v-bind(controlHeight);
    padding: 25rpx;
    box-sizing: border-box;
    flex-grow: 1;

    .rider-evaluate,
    .show-evaluate {
      padding: 25rpx;
      width: 100%;
      box-sizing: border-box;

      .top {
        display: flex;
        justify-content: space-between;
        height: 60rpx;
        line-height: 60rpx;

        .title {
          font-size: 35rpx;
          font-weight: 700;
        }

        .tis {
          font-size: 25rpx;
          color: #939393;
        }

        .radio {
          display: flex;
          align-items: center;
          font-size: 25rpx;
        }
      }

      .rider-info {
        display: flex;
        align-items: center;
        margin: 20rpx 0;

        .avatar-image {
          overflow: hidden;
          margin-right: 20rpx;
          width: 70rpx;
          height: 70rpx;
          border-radius: 12rpx;
        }
      }

      .control-area {
        display: flex;
        flex-direction: column;

        .is-satisfied {
          display: flex;
          justify-content: space-between;

          .button {
            padding: 20rpx 0rpx;
            width: 45%;
            font-size: 30rpx;
            border-radius: 15rpx;
            text-align: center;
            background-color: #f5f5f5;
          }

          .active {
            color: #efa313;
            background-color: #fef9e6;
          }
        }

        .rider-text {
          margin-top: 20rpx;
          padding: 20rpx;
          box-sizing: border-box;
        }

        .overall {
          display: flex;
          align-items: center;

          .label {
            display: inline-block;
            margin-right: 25rpx;
            font-size: 30rpx;
            font-weight: 600;
          }
        }

        .text {
          margin-top: 20rpx;
          padding: 20rpx;
          width: 100%;
          border-radius: 20rpx;
          background-color: #f5f5f5;
          box-sizing: border-box;

          .additional {
            $additional-item-radius-size: 12rpx;

            display: flex;
            flex-wrap: wrap;

            .operation {
              border: 1rpx dashed rgb(62 62 62);
            }

            .additional-item {
              position: relative;
              display: flex;
              justify-content: center;
              align-items: center;
              margin-right: 20rpx;
              margin-bottom: 20rpx;
              width: 120rpx;
              height: 120rpx;
              font-size: 20rpx;
              border-radius: $additional-item-radius-size;
              flex-direction: column;

              .image {
                display: inline;
                width: 100%;
                height: 100%;
                border-radius: $additional-item-radius-size;
              }

              .remove {
                position: absolute;
                top: 0;
                right: 0;
                z-index: 100;
                display: flex;
                justify-content: center;
                align-items: center;
                width: 40rpx;
                height: 40rpx;
                font-size: 25rpx;
                border-radius: 50%;
                color: #fff;
                background-color: #00000070;
                transform: translate(25%, -25%);
              }

              .schedule {
                position: absolute;
                bottom: 0;
                width: 100%;
                background-color: #00000085;
              }
            }
          }
        }

        .dish-good-or-bad {
          .item {
            $dish-item-height: 60rpx;

            display: flex;
            justify-content: space-between;
            align-items: center;
            margin: 20rpx 0rpx;
            width: 100%;

            .dish {
              display: flex;
              align-items: center;
              height: $dish-item-height;
              border-radius: 10rpx;
              background-color: #f6f6f6;
              line-height: $dish-item-height;

              .dish-image {
                width: $dish-item-height;
                height: $dish-item-height;
              }

              .dish-name {
                display: inline-block;
                padding: 0 20rpx;
                font-size: 30rpx;
              }
            }
          }
        }
      }
    }
  }
}
</style>
